package main

import (
	"fmt"
	"github.com/AsynkronIT/goconsole"
	"github.com/AsynkronIT/protoactor-go/actor"
)

type Hello struct{ Who string }
type ParentActor struct{}

func (state *ParentActor) Receive(context actor.Context) {
	switch msg := context.Message().(type) {
	case Hello:
		props := actor.PropsFromProducer(NewChildActor)
		child := context.Spawn(props)
		child.Tell(msg)
	}
}

func NewParentActor() actor.Actor {
	return &ParentActor{}
}

type ChildActor struct{}

func (state *ChildActor) Receive(context actor.Context) {
	switch msg := context.Message().(type) {
	case *actor.Started:
		fmt.Println("Starting, initialize actor here")
	case *actor.Stopping:
		fmt.Println("Stopping, actor is about shut down")
	case *actor.Stopped:
		fmt.Println("Stopped, actor and its children are stopped")
	case *actor.Restarting:
		fmt.Println("Restarting, actor is about restart")
	case Hello:
		fmt.Printf("Hello %v\n", msg.Who)
		panic("Ouch")
	}
}

func NewChildActor() actor.Actor {
	return &ChildActor{}
}

func main() {
	decider := func(reason interface{}) actor.Directive { //返回一个actor决策
		fmt.Println("handling failure for child") //子进程启动失败
		return actor.StopDirective //决策停止actor
	}
	/*newoneforonestrategy返回一个新的主管策略，该策略将决策者的错误指令应用于失败的子进程。如果能够安全地将一个
	失败的孩子与其同龄人或家属隔离，则该策略适用。maxNrOfRetries最大重试次数，持续时间，决策器*/
	supervisor := actor.NewOneForOneStrategy(10, 1000, decider)

	context := actor.EmptyRootContext
	props := actor.
		PropsFromProducer(NewParentActor).
		WithSupervisor(supervisor) //为模板分配监督策略
	pid:= context.Spawn(props)
	context.Send(pid, Hello{Who: "Roger"})

	console.ReadLine()
}
